/*
 * Copyright 2023 Shenzhen Kaihong DID Co., Ltd..
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "location_vendor_lib.h"
#include "location_log.h"
//#define GNSS OHOS::Location::GNSS
#define GPS_MAX_SVS 32
#define GNSS_MAX_SVS 64

enum DL_RET {
  SO_OK = 0,
  LOAD_NOK = -1,
  FUNC_NOK = -2,
};

const int AGMI = 1;
const int GMI = 2;

typedef int64_t GpsUtcTime;
typedef struct {
  size_t size;
  uint16_t flags;
  double latitude;
  double longitude;
  double altitude;
  float speed;
  float bearing;
  float accuracy;
  GpsUtcTime timestamp;
  float veraccuracy;
  float speedaccuracy;
  float bearaccuracy;
} GpsLocation;

typedef struct {
  size_t size;
  int prn;
  float snr;
  float elevation;
  float azimuth;
} GpsSvInfo;

typedef struct {
  size_t size;
  GpsSvInfo sv_list[GPS_MAX_SVS];
  uint32_t ephemeris_mask;
  uint32_t almanac_mask;
  uint32_t used_in_fix_mask;
} GpsSvStatus;

typedef uint8_t GnssConstellationType;
typedef uint8_t GnssSvFlags;

typedef struct {
  size_t size;
  int16_t svid;
  GnssConstellationType constellation;
  float c_n0_dbhz;
  float elevation;
  float zaimuth;
  GnssSvFlags flags;
  float carrier_freq;
} GnssSvInfo;

typedef struct {
  size_t size;
  int numb_svs;
  GnssSvInfo gnss_sv_list[GNSS_MAX_SVS];
} GnssSvStatus;

typedef uint16_t GpsStatusValue;

typedef struct {
  size_t size;
  GpsStatusValue status;
} GpsStatus;

typedef struct {
  size_t size;
  uint16_t year_of_hw;
} GnssSystemInfo;

//read data;
GpsLocation GPSloc;
GpsSvStatus SvState;

typedef unsigned long int pthread_t;

typedef void (*gps_location_callback)(GpsLocation *location);
typedef void (*gps_status_callback)(GpsStatus *status);
typedef void (*gps_sv_status_callback)(GpsSvStatus *sv_info);
typedef void (*gnss_sv_status_callback)(GnssSvStatus *sv_info);
typedef void (*gps_nmea_callback)(GpsUtcTime timestamp, const char *nmea,
                                  int length);
typedef void (*gps_set_capabilities)(uint32_t capbilities);
typedef void (*gps_acquire_wakelock)();
typedef void (*gps_release_wakelock)();
typedef void (*gps_request_utc_time)();
typedef pthread_t (*gps_create_thread)(const char *name, void (*start)(void *),
                                       void *arg);
typedef void (*gnss_set_system_info)(const GnssSystemInfo *info);

/* sprd so callback */
static void location_callback(GpsLocation *location);
static void status_callback(GpsStatus *status);
static void sv_status_callback(GpsSvStatus *sv_status);
static void nmea_callback(GpsUtcTime timestamp, const char *nmea, int length);
static void set_capabilities_callback(uint32_t capabilities);
static void acquire_wakelock_callback();
static void release_wakelock_callback();
static void request_utc_time_callback();
static void gnss_set_system_info_test(const GnssSystemInfo *info);
static void gnss_sv_status_callback_test(GnssSvStatus *sv_info);
pthread_t create_thread_callback(const char *name, void (*start)(void *),
                                 void *arg);
typedef struct {
  size_t size;
  gps_location_callback location_cb;
  gps_status_callback status_cb;
  gps_sv_status_callback sv_status_cb;
  gps_nmea_callback nmea_cb;
  gps_set_capabilities set_capabilities_cb;
  gps_acquire_wakelock acquire_wakelock_cb;
  gps_release_wakelock release_wakelock_cb;
  gps_create_thread create_thread_cb;
  gps_request_utc_time request_utc_time_cb;
  gnss_set_system_info set_system_info_cb;
  gnss_sv_status_callback gnss_sv_status_cb;
} GpsCallbacks; // sprd callback;

GpsCallbacks sGpsCallbacks = {sizeof(GpsCallbacks),
                              location_callback,
                              status_callback,
                              sv_status_callback,
                              nmea_callback,
                              set_capabilities_callback,
                              acquire_wakelock_callback,
                              release_wakelock_callback,
                              create_thread_callback,
                              request_utc_time_callback,
                              gnss_set_system_info_test,
                              gnss_sv_status_callback_test};

typedef int (*pGnssmgt_init)(GpsCallbacks *callbacks);
typedef int (*pGnssmgt_start)(void);
typedef int (*pGnssmgt_stop)(void);
typedef int (*pGnssmgt_cleanup)(void);

/* AGPS PART */
typedef uint16_t ApnIpType;
#define APN_IP_INVALID 0
#define APN_IP_IPV4    1
#define APN_IP_IPV6    2
#define APN_IP_IPV4V6  3

typedef uint16_t AGpsSetIDType;
#define AGPS_SETID_TYPE_NONE    0
#define AGPS_SETID_TYPE_IMSI    1
#define AGPS_SETID_TYPE_MSISDN  2

typedef uint16_t AGpsRefLocationType;
#define AGPS_REF_LOCATION_TYPE_GSM_CELLID       1
#define AGPS_REF_LOCATION_TYPE_UMTS_CELLID      2
#define AGPS_REF_LOCATION_TYPE_MAC              3
#define AGPS_REF_LOCATION_TYPE_LTE_CELLID       4
#define AGPS_REF_LOCATION_TYPE_LTE_CELLID_EX    5
#define AGPS_REF_LOCATION_TYPE_NR_CELLID        8

/* Deprecated, to be removed in the next Android release. */
#define AGPS_REG_LOCATION_TYPE_MAC          3

/** Network types for update_network_state "type" parameter */
#define AGPS_RIL_NETWORK_TYPE_MOBILE        0
#define AGPS_RIL_NETWORK_TYPE_WIFI          1
#define AGPS_RIL_NETWORK_TYPE_MOBILE_MMS    2
#define AGPS_RIL_NETWORK_TYPE_MOBILE_SUPL   3
#define AGPS_RIL_NETWORK_TTYPE_MOBILE_DUN   4
#define AGPS_RIL_NETWORK_TTYPE_MOBILE_HIPRI 5
#define AGPS_RIL_NETWORK_TTYPE_WIMAX        6

/** Requested operational mode for GPS operation. */
typedef uint32_t GpsPositionMode;
/* IMPORTANT: Note that the following values must match
* constants in GpsLocationProvider.java. */
/** Mode for running GPS standalone (no assistance). */
#define GPS_POSITION_MODE_STANDALONE    0
/** AGPS MS-Based mode. */
#define GPS_POSITION_MODE_MS_BASED      1
/**
* AGPS MS-Assisted mode. This mode is not maintained by the platform anymore.
* It is strongly recommended to use GPS_POSITION_MODE_MS_BASED instead.
*/
#define GPS_POSITION_MODE_MS_ASSISTED   2

/** Requested recurrence mode for GPS operation. */
typedef uint32_t GpsPositionRecurrence;
/* IMPORTANT: Note that the following values must match
* constants in GpsLocationProvider.java. */
/** Receive GPS fixes on a recurring basis at a specified period. */
#define GPS_POSITION_RECURRENCE_PERIODIC    0
/** Request a single shot GPS fix. */
#define GPS_POSITION_RECURRENCE_SINGLE      1


/** AGPS type */
typedef uint16_t AGpsType;
#define AGPS_TYPE_SUPL          1
#define AGPS_TYPE_C2K           2

/** AGPS status event values. */
typedef uint16_t AGpsStatusValue;
/** GPS requests data connection for AGPS. */
#define GPS_REQUEST_AGPS_DATA_CONN  1
/** GPS releases the AGPS data connection. */
#define GPS_RELEASE_AGPS_DATA_CONN  2
/** AGPS data connection initiated */
#define GPS_AGPS_DATA_CONNECTED     3
/** AGPS data connection completed */
#define GPS_AGPS_DATA_CONN_DONE     4
/** AGPS data connection failed */
#define GPS_AGPS_DATA_CONN_FAILED   5

typedef struct {
    /** set to sizeof(AGpsStatus) */
    size_t                  size;

    AGpsType                type;
    AGpsStatusValue         status;

    /**
     * Must be set to a valid IPv4 address if the field 'addr' contains an IPv4
     * address, or set to INADDR_NONE otherwise.
     */
    uint32_t                ipaddr;

    /**
     * Must contain the IPv4 (AF_INET) or IPv6 (AF_INET6) address to report.
     * Any other value of addr.ss_family will be rejected.
     */
    // struct sockaddr_storage addr;
} AGpsStatus;

/**
 * Callback with AGPS status information. Can only be called from a thread
 * created by create_thread_cb.
 */
typedef void (* agps_status_callback)(AGpsStatus* status);
typedef void (*agps_ril_request_set_id)(uint32_t flags);
typedef void (*agps_ril_request_ref_loc)(uint32_t flags);
typedef pthread_t (* gps_create_thread)(const char* name,void (*start)(void *),void* arg);

/* CellID for 2G, 3G and LTE, used in AGPS. */
typedef struct {
        AGpsRefLocationType type;
        /** Mobile Country Code. */
        uint16_t mcc;
        /** Mobile Network Code .*/
        uint16_t mnc;
        /** Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE,
        * lac is populated with tac, to ensure that we don't break old clients that
        * might rely in the old (wrong) behavior.
        */
        uint16_t lac;
        /** Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE. */
        uint32_t cid;

        /** Tracking Area Code in LTE. */
        uint16_t tac;
        /** Physical Cell id in LTE (not used in 2G and 3G) */
        uint16_t pcid;
} AGpsRefLocationCellID;

typedef struct {
    uint8_t mac[6];
} AGpsRefLocationMac;

typedef struct {
        /** Mobile Country Code. */
        uint16_t mcc;
        /** Mobile Network Code .*/
        uint16_t mnc;
        /** Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE. */
        uint64_t cid;
        /** Tracking Area Code in LTE. */
        uint32_t tac;
        /** Physical Cell id in LTE (not used in 2G and 3G) */
        uint16_t pcid;
        /** ARFCN used for SSB or CSI-RS measurements, 0..3279165. */
        uint32_t arfcn_nr;
} AGpsRefLocationCellID_NR_t;

/** Represents ref locations */
typedef struct {
    AGpsRefLocationType type;
    union {
        AGpsRefLocationCellID       cellID;
        AGpsRefLocationMac          mac;
        AGpsRefLocationCellID_NR_t  cellID_nr;
    } u;
} AGpsRefLocation;

/** Callback structure for the AGPS interface. */
typedef struct {
    agps_status_callback status_cb;
    gps_create_thread create_thread_cb;
} AGpsCallbacks;

typedef struct {
    agps_ril_request_set_id request_setid;
    agps_ril_request_ref_loc request_refloc;
    gps_create_thread create_thread_cb;
} AGpsRilCallbacks;

/* AGMI interface*/
void gnssmgt_agps_ril_setRefLoc(
        const AGpsRefLocation *refLocation, size_t szStruct);
void gnssmgt_agps_ril_setSetID(AGpsSetIDType type, const char *setid);

/* sprd so callback */
static void agnss_status_callback(AGpsStatus* status);
static void agnss_ril_request_set_id_callback(uint32_t flags);
static void agnss_ril_request_ref_loc_callback(uint32_t flags);
pthread_t agnss_create_thread_cb(const char* name, void (*start)(void *), void* arg);

typedef int (*pAGnssmgt_init)(AGpsCallbacks* callbacks);
typedef int (*pAGnssmgt_setPosMode)(
        GpsPositionMode         mode,
        GpsPositionRecurrence   recurrence,
        uint32_t                minInterval,
        uint32_t                prefAccuracy,
        uint32_t                prefTime);
typedef int (*pAGnssmgt_agps_closeConn)(void);
typedef int (*pAGnssmgt_agps_openFailed)(void);
typedef int (*pAGnssmgt_set_server)(AGpsType type, const char* hostname, int port);
typedef int (*pAGnssmgt_open_conn)(const char* apn);
typedef int (*pAGnssmgt_agps_openWithApnIpType)(const char *apn, ApnIpType apnIpType);
typedef int (*pAGnssmgt_ril_init)(AGpsRilCallbacks *callbacks);
typedef int (*pAGnssmgt_ril_ref_location)(const AGpsRefLocation *refLocation, size_t szStruct);
typedef int (*pAGnssmgt_set_setid)(AGpsSetIDType type, const char *setid);
typedef int (*pAGnssmgt_set_RefLoc)(const AGpsRefLocation *refLocation, size_t szStruct);
typedef int (*pAGnssmgt_updateNwState)(int connected, int type, int roaming, const char* extraInfo);
typedef int (*pAGnssmgt_updateNwAvailability)(int avaiable, const char *apn);
typedef int (*pAGnssmgt_ril_set_id)(AGpsSetIDType type, const char *setid);
typedef int (*pAGnssmgt_ril_update_network_availability)(int avaiable, const char *apn);
typedef int (*pAGnssmgt_ril_update_network_state)(int connected, int type, int roaming, const char* extraInfo);

pGnssmgt_init gps_init=NULL;
pGnssmgt_start gps_start=NULL;
pGnssmgt_stop gps_stop=NULL;
pGnssmgt_cleanup gps_cleanup=NULL;
pAGnssmgt_init agps_init=NULL;
pAGnssmgt_setPosMode agps_setPosMode=NULL;
pAGnssmgt_set_server agps_set_server=NULL;
pAGnssmgt_open_conn agps_open_conn=NULL;
pAGnssmgt_updateNwState agps_updateNwState=NULL;
pAGnssmgt_updateNwAvailability agps_updateNwAvailability=NULL;
pAGnssmgt_set_setid agps_set_setid=NULL;
pAGnssmgt_set_RefLoc agps_set_RefLoc=NULL;
pAGnssmgt_agps_closeConn agps_close_conn=NULL;
pAGnssmgt_agps_openFailed agps_open_failed=NULL;
pAGnssmgt_agps_openWithApnIpType agps_open_with_apn=NULL;
pAGnssmgt_ril_init  agps_ril_init=NULL;
pAGnssmgt_ril_ref_location agps_ril_ref_location=NULL;
pAGnssmgt_ril_set_id agps_ril_set_id=NULL;
pAGnssmgt_ril_update_network_availability agps_ril_net_ability=NULL;
pAGnssmgt_ril_update_network_state agps_ril_net_state=NULL;



